package cn.edu.jxust.core.domain.repository.impl;

import cn.edu.jxust.common.domain.dto.AutomaticData;
import cn.edu.jxust.core.infrastructure.OneNetConst;
import cn.edu.jxust.common.domain.entity.Account;
import cn.edu.jxust.common.domain.entity.Air;
import cn.edu.jxust.common.domain.entity.AirType;
import cn.edu.jxust.common.domain.entity.Device;
import cn.edu.jxust.common.domain.valobj.AirDetail;
import cn.edu.jxust.core.infrastructure.mapper.AirMapper;
import cn.edu.jxust.core.infrastructure.mapper.AirtypeMapper;
import cn.edu.jxust.core.infrastructure.mapper.DeviceMapper;
import cn.edu.jxust.common.response.Result;
import cn.edu.jxust.common.response.ResultUtils;
import cn.edu.jxust.common.response.enums.ResultStatus;
import cn.edu.jxust.core.domain.repository.AirService;
import cn.edu.jxust.core.infrastructure.util.AqiUtils;
import cn.edu.jxust.core.infrastructure.util.Const;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author QiuKangming
 * @since 2020-06-29
 */
@Service
public class AirServiceImpl extends ServiceImpl<AirMapper, Air> implements AirService {

    @Resource
    private AirMapper airMapper;
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private AirtypeMapper airtypeMapper;

    /**
     * double 设置小数位
     */
    private final DecimalFormat df = new DecimalFormat("0.000");

    /**
     * 自动采集数据保存
     * @param data AutomaticData
     * @return Result
     */
    @Override
    public Result saveByAutoData(AutomaticData data) {

        //设备上传的数据 有 IMEI 码, 人工录入的没有, 前者不需要设置createUserid, 后者需要
        boolean isMan = data.getIMEI() == null;
        Integer userId = null;
        if(isMan){
            userId = ((Account) SecurityUtils.getSubject().getPrincipal()).getId();
        }
        //将AutomaticData转换成 Air 对象
        int i = airMapper.insert(
                Air.builder()
                        .deviceId(isMan ? null : deviceMapper.getIdByIMEI(data.getIMEI()))
                        .airtypeId(airtypeMapper.getIdByAirName(data.getDataType()))
                        .createUserid(userId)
                        .concentration(Double.parseDouble(data.getValue()))
                        .isException(data.getIsException())
                        .build()
        );
        if(!isMan){
            return null;
        }else{
            return i == 1
                    ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "添加气体记录成功")
                    : ResultUtils.resultWithoutData(ResultStatus.FAILED, "添加气体记录失败");
        }

    }

    /**
     * 获取上一个小时上传数据的设备id号
     * @param date 日期
     * @param begin 开始时间
     * @param end 结束时间
     * @return List<Integer>
     */
    @Override
    public List<Integer> getLastHourDeviceIds(String date, String begin, String end) {

        return airMapper.getLastHourDeviceIds(date, begin, end);

    }

    /**
     * 获取前一天设备上传的PM2.5和PM10的设备id号
     * @param date 日期
     * @param begin 开始时间
     * @param end 结束时间
     * @return List<Integer>
     */
    @Override
    public List<Integer> getLastDayPMDeviceIds(String date, String begin, String end) {

        int pm25Id = airtypeMapper.getIdByAirName(OneNetConst.PM25);
        int pm10Id = airtypeMapper.getIdByAirName(OneNetConst.PM10);
        return airMapper.getLastDayPMDeviceIds(date, Arrays.asList(pm25Id, pm10Id), begin, end);

    }

    /**
     * 获取上一个小时除PM之外的气体浓度信息
     * @param deviceId 设备id号
     * @param date 日期
     * @param begin 开始时间
     * @param end 结束时间
     * @return List<Air>
     */
    @Override
    public List<Air> getLastHourAirListNoPM(Integer deviceId, String date, String begin, String end) {

        int pm25Id = airtypeMapper.getIdByAirName(OneNetConst.PM25);
        int pm10Id = airtypeMapper.getIdByAirName(OneNetConst.PM10);
        QueryWrapper<Air> wrapper = new QueryWrapper<>();
        wrapper.notIn("airtype_id", pm25Id, pm10Id)
                .eq("device_id", deviceId)
                .eq("create_date", date)
                .between("create_time", begin, end)
                .eq("is_exception", 1)
                .eq("status", 1);
        return list(wrapper);

    }

    /**
     * 获取前一天PM2.5和OM10的浓度信息
     * @param deviceId 设备id号
     * @param date 日期
     * @param begin 开始时间
     * @param end 结束时间
     * @return List<Air>
     */
    @Override
    public List<Air> getLastDayPM25AndPM10List(Integer deviceId, String date, String begin, String end) {

        int pm25Id = airtypeMapper.getIdByAirName(OneNetConst.PM25);
        int pm10Id = airtypeMapper.getIdByAirName(OneNetConst.PM10);
        QueryWrapper<Air> wrapper = new QueryWrapper<>();
        wrapper.in("airtype_id", pm25Id, pm10Id)
                .eq("device_id", deviceId)
                .eq("create_date", date)
                .between("create_time", begin, end)
                .eq("is_exception", 1)
                .eq("status", 1);
        return list(wrapper);

    }

    /**
     * 分页获取有问题的Air数据
     * @param page 第几页
     * @param size 一页几条数据
     * @param deviceId 设备id号，为空则查询所有设备
     * @param airType 气体类型， 为空则查询所有气体信息
     * @param beginDate 开始时间，
     * @param endDate 结束时间
     * @return Result
     */
    @Override
    @Transactional(readOnly = true)
    public Result getHasExceptionAir(Integer page, Integer size, Integer deviceId, Integer airType, String beginDate, String endDate) {

        //检查设备是否正常,即是否绑定监测点
        int flg = deviceMapper.deviceIsBinding(deviceId);
        if(Const.NOT_BINDING.equals(flg)){
            //设备未绑定
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "暂无设备监测数据异常信息, 请检查您的设备是否有绑定监测点?");
        }
        //1. 封装查询条件
        QueryWrapper<Air> wrapper = new QueryWrapper<>();

        wrapper.eq("device_id", deviceId);
        if(airType != null){
            wrapper.eq("airtype_id", airType);
        }
        wrapper.between("create_date", beginDate, endDate);
        wrapper.eq("is_exception", 0);
        wrapper.orderByDesc("create_date", "create_time");

        IPage<Air> airPage = airMapper.selectPage(new Page<>(page, size), wrapper);
        if(airPage.getRecords() == null || airPage.getRecords().isEmpty()){
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "没有任何有异常气体信息");
        }

        IPage<AirDetail> pageInfo = new Page<>();

        pageInfo.setCurrent(airPage.getCurrent());
        pageInfo.setRecords(this.toAirDetailList(airPage.getRecords()));
        pageInfo.setPages(airPage.getPages());
        pageInfo.setSize(airPage.getSize());
        pageInfo.setTotal(airPage.getTotal());

        return ResultUtils.resultWithData(ResultStatus.SUCCESS, pageInfo);
    }

    /**
     * 将 List<Air> airList 转换成 List<AirDetail>
     * @param airList air列表
     * @return List<AirDetail>
     */
    private List<AirDetail> toAirDetailList(List<Air> airList){

        List<AirDetail> airDetailList = new ArrayList<>(airList.size());
        airList.forEach(air -> airDetailList.add(toAirDetail(air)));
        return airDetailList;

    }

    /**
     * 将 Air 转换成 AirDetail
     * @param air air
     * @return AirDetail
     */
    private AirDetail toAirDetail(Air air){

        Device device = deviceMapper.selectById(air.getDeviceId());
        AirType airType = airtypeMapper.selectById(air.getAirtypeId());
        double standaredCon = Double.parseDouble(df.format(AqiUtils.getAirStandaredCon(airType.getAirName(), AqiUtils.HAQI)));
        double concentration = Double.parseDouble(df.format(air.getConcentration()));
        double differ = Double.parseDouble(df.format(concentration - standaredCon));
        return AirDetail.builder()
                .id(air.getId())
                .deviceId(air.getDeviceId())
                .imei(device.getNbDeviceId())
                .deviceDescription(device.getDescription())
                .airtypeId(air.getAirtypeId())
                .airName(airType.getAirName())
                .concentration(concentration)
                .standardCon(standaredCon)
                .differ(differ)
                .createDate(air.getCreateDate())
                .createTime(air.getCreateTime())
                .isException(air.getIsException())
                .build();

    }

}
